// PluginSetup.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>

#include "PluginDecl.h"

#define TOTALBYTES    2048
#define PATHSIZE      512
#define MAX_FMT		  384

BYTE Buffer[TOTALBYTES];
CHAR DllPath[TOTALBYTES];
LPSTR Path;
HMODULE DllModules[MAXFILES];
PluginData *PluginApp;
TAppMessageFunction MessageFunc;
int nModules = 0;

void LogWrite(LPSTR lpstrMessage)
{
	OutputDebugString(lpstrMessage);
	OutputDebugString("\n");
}

void LogWrite(LPSTR lpstrFormat, DWORD value)
{
	char lpstrBuf[MAX_FMT];
	wsprintf(lpstrBuf, lpstrFormat, value);
	OutputDebugString(lpstrBuf);
	OutputDebugString("\n");
}

void LogWrite(LPSTR lpstrFormat, LPSTR value)
{
	char lpstrBuf[MAX_FMT];
	wsprintf(lpstrBuf, lpstrFormat, value);
	OutputDebugString(lpstrBuf);
	OutputDebugString("\n");
}

// Allocates a string buffer and returns it
LPTSTR GetPathValue()
{
	DWORD BufferSize = TOTALBYTES;
	DWORD nSuccess = GetCurrentDirectory(BufferSize, (LPTSTR)Buffer);
	if (nSuccess == 0)
	{
		LogWrite("Failed to get path to current directory.");
		return NULL;
	}
	return (LPTSTR)Buffer;
}

// Load list of configuration strings from registry
void LoadStrings()
{
	Path = GetPathValue();
	LogWrite("Path : ");
	LogWrite(Path);
}

// Free list of configuration strings from registry
void FreeStrings()
{
	//nothing
}

void FreeLibraries()
{
	for (int k = 0; k < MAXFILES; k++) {
		if (DllModules[k] != 0) {
			if (FreeLibrary (DllModules[k]) == 0)
			{
				LogWrite("Could not free a library at %d", k);
			}
			DllModules[k] = 0;
		}
	}
}

// Load plugin DLLs as libraries using configuration string
void LoadLibraries(LPSTR lpszPath)
{
	int k = 0;
	for (int k = 0; k < MAXFILES; k++) {
		DllModules[k] = 0;
	}

	k = 0;
	nModules = 0;

	lstrcpy(DllPath, lpszPath);
	lstrcat(DllPath, "\\Plugins\\*.dll");

	WIN32_FIND_DATA FindFileData;
	HANDLE hFind;
	
	hFind = FindFirstFile(DllPath, &FindFileData);
	if (hFind == INVALID_HANDLE_VALUE)
	{
		LogWrite("Invalid File Handle. GetLastError reports %d", GetLastError ());
		return;
	}
	else 
	{
		LogWrite("The first file found is %s", FindFileData.cFileName);
		lstrcpy(DllPath, lpszPath);
		lstrcat(DllPath, "\\Plugins\\");
		lstrcat(DllPath, FindFileData.cFileName);
		DllModules[k] = LoadLibrary(DllPath);
		if (DllModules[k] == NULL)
		{
			LogWrite("Library not loaded at path %s", DllPath);
		}
		nModules = 1;
		while (FindNextFile(hFind, &FindFileData) != 0 && k < MAXFILES)
		{
			LogWrite("The next file found is %s", FindFileData.cFileName);
			lstrcpy(DllPath, lpszPath);
			lstrcat(DllPath, "\\Plugins\\");
			lstrcat(DllPath, FindFileData.cFileName);
			k++;
			DllModules[k] = LoadLibrary(DllPath);
			if (DllModules[k] == NULL)
			{
				LogWrite("Library not loaded at path %s", DllPath);
			}
			nModules = k + 1;
		}
		FindClose(hFind);
	}
}

// Execute configuration functions
void ApplyLibraries()
{
	//for each DLL that we load, we must call its function
	for (int k = 0; k < nModules; k++)
	{
		if(DllModules[k] != NULL)
		{
			TDllPluginFunction func = (TDllPluginFunction)GetProcAddress(DllModules[k], "DllPluginFunction");
			if (!func)
			{
				LogWrite("DllPluginFunction not loaded for DLL. GetLastError returned %d", GetLastError());
			}
			else
			{
				func(0, PluginApp);
			}
		}
	}
}

// Load plugins from specified path
void Startup()
{
	LoadStrings();
	LoadLibraries(Path);
	ApplyLibraries();
}

void Exit()
{
	FreeLibraries();
	FreeStrings();
}

void OnAttach()
{
	LogWrite("Attaching to app...");
	Startup();
}

void OnDetach()
{
	LogWrite("Detaching from app...");
	Exit();
}

void OnMessage(PluginData *pData)
{
	LogWrite("Message received by PluginSetup.");
	PluginApp->iValue = 1;
	PluginApp->pValue = pData;
	MessageFunc();
}

void AppAttach(PluginData* app)
{
	LogWrite("Attaching...");
	MessageFunc = (TAppMessageFunction)(app->pValue);
	PluginApp = app;
	OnAttach();
}

void AppDetach(PluginData* app)
{
	LogWrite("Detaching...");
	app->pValue = 0;
	app->iValue = 0;
	PluginApp = app;
	OnDetach();
}

void AppMessage(PluginData* app, PluginData* pData)
{
	PluginApp = app;
	LogWrite("Sending message...");
	OnMessage(pData);
}

HMODULE* GetDllModules()
{
	return DllModules;
}

int GetNumDllModules()
{
	return nModules;
}

PluginData* GetPluginApp()
{
	return PluginApp;
}

BOOL WINAPI DllMain(
	HINSTANCE hInstDll,
	DWORD dwReason,
	LPVOID lpvReserved)
{
	return TRUE;
}